﻿using System;
using System.Data;
using System.Text;
using System.Collections;
using System.Globalization;

using BizElements.Core;
using BizElements.Core.ProviderComponents;

namespace BizElements.Core.PostgreSql
{
    sealed class PostgreSqlSelectRenderer : ISelectRenderer
    {
        #region Render.

        public void Render(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            AppendSelectAndDistinctKeyWords(select, output);            
            AppendSelectList(select, dbms, output, parameters);
            AppendFromClause(select, dbms, output);
            AppendWhereClause(select, dbms, output, parameters);
            AppendGroupByClause(select, dbms, output, parameters);
            AppendHavingClause(select, dbms, output, parameters);
            AppendOrderByClause(select, dbms, output, parameters);
            AppendLimitClause(select, output);
        }

        private static void AppendSelectAndDistinctKeyWords(SelectStatement select, StringBuilder output)
        {
            // SELECT.
            output.Append("SELECT ");
            if (select.Distinct)
                output.Append("DISTINCT ");
        }

        private static void AppendLimitClause(SelectStatement select, StringBuilder output)
        {
            // LIMIT comes last - after ORDER BY.
            if (select.Top > 0)
            {
                output.Append(" LIMIT ");
                output.Append(select.Top.ToString(CultureInfo.InvariantCulture));
                output.Append(" ");
            }
        }

        private static void AppendSelectList(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            // Select list.
            if (select.SelectList != null && select.SelectList.Count > 0)
                select.SelectList.Render(dbms, output, parameters);
            else
                output.Append("*");
        }

        private static void AppendFromClause(SelectStatement select, DbmsType dbms, StringBuilder output)
        {
            // FROM.
            output.Append(" ");
            if (select.Relations != null)
            {
                select.Relations.RenderFromClause(select.FromTable, dbms, output);
            }
            else
            {
                // If no relations have been specified.
                output.Append("FROM ");
                select.FromTable.RenderTableName(dbms, output);
                // AS may not be used between table name and alias because Oracle doesn't that syntax.
                if (select.FromTable.Alias != select.FromTable.TableName)
                {
                    output.Append(" ");
                    select.FromTable.RenderAlias(dbms, output);
                }
            }
        }

        private static void AppendWhereClause(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            // WHERE.
            if (select.Where != null && !select.Where.IsEmpty)
            {
                output.Append(" WHERE ");
                select.Where.Render(dbms, output, parameters);
            }
        }

        private static void AppendGroupByClause(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            // GROUP BY.
            if (select.GroupBy != null && select.GroupBy.Fields.Count > 0)
            {
                output.Append(" ");
                select.GroupBy.Render(dbms, output, parameters);
            }
        }

        private static void AppendHavingClause(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            // HAVING.
            if (select.Having != null && !select.Having.IsEmpty)
            {
                output.Append(" HAVING ");
                select.Having.Render(dbms, output, parameters);
            }
        }

        private static void AppendOrderByClause(SelectStatement select, DbmsType dbms, StringBuilder output, DbParameterCollection parameters)
        {
            // ORDER BY.
            if (select.OrderBy != null && select.OrderBy.Count > 0)
            {
                output.Append(" ");
                select.OrderBy.Render(dbms, output, parameters);
            }
        }

        #endregion
    }
}